import enum
import random
import time
import numpy as np
import pandas as pd
import simpy
import copy
from tqdm import tqdm
from matplotlib import pyplot as plt
from collections import OrderedDict
from typing import List, Dict

"""-*- coding: utf-8 -*-"""

# 任务列表
# CraneTaskQueue =[{'StartPosition': [32, 1, 1], 'EndPosition': [32, 6, 1]},
# {'StartPosition': [31, 1, 2], 'EndPosition': [31, 6, 1]},
#  {'StartPosition': [26, 3, 1], 'EndPosition': [26, 6, 1]},
#  {'StartPosition': [22, 1, 2], 'EndPosition': [22, 6, 1]},
#  {'StartPosition': [19, 3, 1], 'EndPosition': [14, 12, 2]},
# {'StartPosition': [6, 3, 1], 'EndPosition': [41, 5, 1]},
# {'StartPosition': [54, 2, 2], 'EndPosition': [54, 6, 1]},
#  {'StartPosition': [63, 7, 2], 'EndPosition': [63, 6, 1]},
# {'StartPosition': [55, 1, 1], 'EndPosition': [55, 6, 1]}]

# ReachStackerTaskQueue =[{'StartPosition': [2, 7, 2], 'EndPosition': [2, 13, 1]},
#  {'StartPosition': [7, 4, 1], 'EndPosition': [7, 13, 1]},
# {'StartPosition': [46, 11, 1], 'EndPosition': [46, 13, 1]},
# {'StartPosition': [30, 9, 2], 'EndPosition': [30, 13, 1]},
# {'StartPosition': [11, 12, 2], 'EndPosition': [11, 13, 1]},
#  {'StartPosition': [21, 10, 2], 'EndPosition': [21, 6, 1]},
# {'StartPosition': [39, 8, 1], 'EndPosition': [39, 13, 1]},
# {'StartPosition': [26, 10, 2], 'EndPosition': [26, 6, 1]},
# {'StartPosition': [4, 8, 2], 'EndPosition': [4, 6, 1]},
# {'StartPosition': [22, 4, 1], 'EndPosition': [22, 6, 1]},
#  {'StartPosition': [45, 8, 2], 'EndPosition': [45, 6, 1]}]

# CraneTaskQueue =[{'StartPosition': [52, 4, 1], 'EndPosition': [52, 6, 1]}, {'StartPosition': [48, 4, 1], 'EndPosition': [51, 9, 1]}, {'StartPosition': [45, 8, 2], 'EndPosition': [45, 6, 1]}, {'StartPosition': [42, 11, 1], 'EndPosition': [42, 6, 1]}, {'StartPosition': [39, 3, 1], 'EndPosition': [26, 7, 2]}, {'StartPosition': [30, 2, 2], 'EndPosition': [30, 6, 1]}, {'StartPosition': [19, 11, 1], 'EndPosition': [19, 6, 1]}, {'StartPosition': [11, 11, 1], 'EndPosition': [11, 6, 1]}, {'StartPosition': [7, 3, 1], 'EndPosition': [57, 1, 1]}, {'StartPosition': [4, 9, 1], 'EndPosition': [4, 6, 1]}, {'StartPosition': [2, 11, 1], 'EndPosition': [2, 6, 1]}]
# ReachStackerTaskQueue =[{'StartPosition': [10, 11, 1], 'EndPosition': [10, 6, 1]}, {'StartPosition': [11, 8, 1], 'EndPosition': [11, 13, 1]}, {'StartPosition': [15, 10, 2], 'EndPosition': [15, 13, 1]}, {'StartPosition': [16, 11, 1], 'EndPosition': [16, 13, 1]}, {'StartPosition': [32, 8, 2], 'EndPosition': [32, 6, 1]}, {'StartPosition': [36, 12, 1], 'EndPosition': [36, 13, 1]}, {'StartPosition': [49, 4, 1], 'EndPosition': [49, 13, 1]}, {'StartPosition': [54, 12, 1], 'EndPosition': [54, 13, 1]}, {'StartPosition': [57, 12, 2], 'EndPosition': [57, 13, 1]}]
CraneTaskQueue = [{'StartPosition': [60, 2, 1], 'EndPosition': [60, 6, 1]}, {'StartPosition': [32, 10, 2], 'EndPosition': [32, 6, 1]}, {'StartPosition': [39, 10, 1], 'EndPosition': [39, 6, 1]}, {'StartPosition': [33, 7, 1], 'EndPosition': [33, 6, 1]}, {'StartPosition': [53, 12, 2], 'EndPosition': [53, 6, 1]}, {'StartPosition': [56, 9, 1], 'EndPosition': [56, 6, 1]}, {'StartPosition': [53, 3, 1], 'EndPosition': [14, 11, 1]}, {'StartPosition': [5, 2, 1], 'EndPosition': [5, 6, 1]}, {'StartPosition': [4, 2, 2], 'EndPosition': [4, 6, 1]}]
ReachStackerTaskQueue = [{'StartPosition': [50, 11, 2], 'EndPosition': [50, 6, 1]}, {'StartPosition': [65, 7, 2], 'EndPosition': [65, 13, 1]}, {'StartPosition': [36, 4, 1], 'EndPosition': [16, 12, 1]}, {'StartPosition': [44, 7, 1], 'EndPosition': [44, 6, 1]}, {'StartPosition': [40, 4, 1], 'EndPosition': [40, 13, 1]}, {'StartPosition': [19, 12, 2], 'EndPosition': [19, 6, 1]}, {'StartPosition': [27, 4, 1], 'EndPosition': [14, 5, 1]}, {'StartPosition': [36, 11, 1], 'EndPosition': [36, 13, 1]}, {'StartPosition': [59, 12, 2], 'EndPosition': [59, 13, 1]}, {'StartPosition': [18, 11, 1], 'EndPosition': [18, 13, 1]}, {'StartPosition': [48, 12, 1], 'EndPosition': [48, 13, 1]}]
ContainerLocationTablePath = "./箱位状态表(20240325目前可用).xlsx"
# 获取集装箱箱位信息
ContainerLocationTable = pd.read_excel(ContainerLocationTablePath)
# 建立集装箱信息三维矩阵
ContainerLocationMatrix = np.zeros((2, 14, 66))
for index, row in ContainerLocationTable.iterrows():
    ContainerLocationMatrix[row['层位'] - 1, row['栈位'] - 1, row['贝位'] - 1] = row['占用状态']
RoadStack = [5, 6, 13, 14]
"""-------------------------------------超参数定义---- ---------------------------------"""
# 种群大小
POP_SIZE = 50
# 交叉概率
CROSS_RATE = 0.8
# 变异概率
MUTATION_RATE = 0.1
# 迭代次数
ITERATION = 40
# 精英保留数
ELITE_RETAIN = 3
# 开始进化
START_EVOLUTION = False
"""-------------------------------------工具函数定义-------------------------------------"""


def Rs_TaskFeasiblityCheck(Matrix, Rstask, Cranetask):
    # 将箱位状态矩阵中一层和二层的占用状态进行求和
    ContainerCountMatrix = Matrix[0] + Matrix[1]
    for elem in Rstask:
        TaskFeasiblity = False
        StartPosition = elem['StartPosition']
        EndPosition = elem['EndPosition']
        # 获取任务起始位置栈位上方的栈位状态
        UpStackData = ContainerCountMatrix[(StartPosition[1] - 1) + 1:15, StartPosition[0] - 1]
        # 获取任务起始位置栈位下方的栈位状态
        DownStackData = np.flip(ContainerCountMatrix[4:(StartPosition[1] - 1), StartPosition[0] - 1])
        if np.count_nonzero(UpStackData) == 0 or np.count_nonzero(DownStackData) == 0:
            TaskFeasiblity = True
        elif np.count_nonzero(UpStackData) == 1 and UpStackData[0] <= ContainerCountMatrix[
            StartPosition[1] - 1, StartPosition[0] - 1] and UpStackData[0] != 0:
            TaskFeasiblity = True
        elif np.count_nonzero(DownStackData) == 1 and DownStackData[0] <= ContainerCountMatrix[
            StartPosition[1] - 1, StartPosition[0] - 1] and DownStackData[0] != 0:
            TaskFeasiblity = True
        else:
            TaskFeasiblity = False
        # 如果抓取位置不可达，查询轨道吊任务队列是否有相关贝位的任务
        if TaskFeasiblity == False:
            if any([elem_['StartPosition'][0] == StartPosition[0] and 7 <= elem_['StartPosition'][1] <= 12 for elem_ in
                    Cranetask]):
                pass
            else:
                return False
        # 获取任务起始位置栈位上方的栈位状态
        UpStackData = ContainerCountMatrix[(EndPosition[1] - 1) + 1:15, EndPosition[0] - 1]
        # 获取任务起始位置栈位下方的栈位状态
        DownStackData = np.flip(ContainerCountMatrix[4:(EndPosition[1] - 1), EndPosition[0] - 1])
        if np.count_nonzero(UpStackData) == 0 or np.count_nonzero(DownStackData) == 0:
            TaskFeasiblity = True
        elif np.count_nonzero(UpStackData) == 1 and UpStackData[0] <= ContainerCountMatrix[
            EndPosition[1] - 1, EndPosition[0] - 1] and UpStackData[0] != 0:
            TaskFeasiblity = True
        elif np.count_nonzero(DownStackData) == 1 and DownStackData[0] <= ContainerCountMatrix[
            EndPosition[1] - 1, EndPosition[0] - 1] and DownStackData[0] != 0:
            TaskFeasiblity = True
        else:
            TaskFeasiblity = False
        # 如果抓取位置不可达，查询轨道吊任务队列是否有相关贝位的任务
        if TaskFeasiblity == False:
            if any([elem_['StartPosition'][0] == EndPosition[0] for elem_ in Cranetask]):
                pass
            else:
                return False
    return True


def check_UPORDOWN_sorting(lst, ascending=True):
    dict_2nd = {}

    for item in lst:
        key = tuple(item[:2])
        if key in dict_2nd:
            dict_2nd[key].append(item[2])
        else:
            dict_2nd[key] = [item[2]]

    if all(len(values) == 1 for values in dict_2nd.values()):
        return False
    for values in dict_2nd.values():
        if ascending:
            if values != sorted(values):
                return False
        else:
            if values != sorted(values, reverse=True):
                return False
    return True


# ascending = True表示升序，False表示降序,升序表示由内向外，降序表示由外向内
def check_INNEROROUTER_sorting(lst, ascending=True):
    dict_1nd = {}

    for item in lst:
        key = item[0]
        stack = item[1]
        if stack <= 6 or stack >= 13:
            continue
        if key in dict_1nd:
            dict_1nd[key].append(abs(item[1] - 9.5))
        else:
            dict_1nd[key] = [abs(item[1] - 9.5)]

    if all(len(values) == 1 for values in dict_1nd.values()):
        return False
    for values in dict_1nd.values():
        if ascending:
            if values != sorted(values):
                return False
        else:
            if values != sorted(values, reverse=True):
                return False
    return True


# def check_allocation_constraints(lst):
#     size = len(lst) // 2
#     order = lst[:size]
#     machine = lst[size:]
#     CraneTaskList = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 1]
#     ReachStackerTaskList = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 0]
#     if any([elem['StartPosition'][1] <= 3 or elem['EndPosition'][1] <= 3 for elem in ReachStackerTaskList]):
#         return False
#     if any([elem['StartPosition'][1] >= 13 or elem['EndPosition'][1] >= 13 for elem in CraneTaskList]):
#         return False
#     return True


def para_check(func):
    def wapper(*args, **kwargs):
        typed = args[-1]
        if typed not in ['order', 'machine']:
            raise ValueError('参数输入错误')
        else:
            res = func(*args, **kwargs)
        return res

    return wapper


"""-------------------------------------个体类定义-------------------------------------"""


# class Individuals:
#     def __init__(self, DNA=None):
#         self._DNA = DNA
#         self._fitness = 0
#
#     @property
#     def fitness(self):
#         return self._fitness
#
#     @fitness.setter
#     def fitness(self, value):
#         self._fitness = value
#
#     @property
#     def DNA(self):
#         return self._DNA
#
#     @DNA.setter
#     def DNA(self, value):
#         self._DNA = value
#
#     # DNA可行性判断
#     def DNAFeasibility(self):
#         size = len(self.DNA) // 2
#         order = self.DNA[:size]
#         machine = self.DNA[size:]
#         CraneTaskList = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 1]
#         ReachStackerTaskList = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 0]
#         CraneStartTaskList = [task['StartPosition'] for task in CraneTaskList]
#         CraneEndTaskList = [task['EndPosition'] for task in CraneTaskList]
#         ReachStackerStartTaskList = [task['StartPosition'] for task in ReachStackerTaskList]
#         ReachStackerEndTaskList = [task['EndPosition'] for task in ReachStackerTaskList]
#         A = check_UPORDOWN_sorting(CraneStartTaskList, False)
#         B = check_UPORDOWN_sorting(CraneEndTaskList, True)
#         C = check_UPORDOWN_sorting(ReachStackerStartTaskList, False)
#         D = check_UPORDOWN_sorting(ReachStackerEndTaskList, True)
#         E = check_INNEROROUTER_sorting(ReachStackerStartTaskList, False)
#         F = check_INNEROROUTER_sorting(ReachStackerEndTaskList, True)
#         G = Rs_TaskFeasiblityCheck(ContainerLocationMatrix, ReachStackerTaskList, CraneTaskList)
#         H = check_allocation_constraints(self.DNA)
#         if not (A or B or C or D or E or F or not G or not H):
#             return True
#         else:
#             return False


"""-------------------------------------种群类定义-------------------------------------"""


# class Population:
#     def __init__(self):
#         # 种群规模
#         self.POP_SIZE = POP_SIZE
#         # 任务列表
#         self.TaskList = TaskList
#         # 当代种群
#         self.population = []
#         # 候选种群
#         self.candidate = []
#         # 子代种群
#         self.child = []
#         # 当代种群最优个体
#         self.best = Individuals()
#         # 当代种群最优适应度
#         self.best_fitness = 10e8
#         # 适应度函数
#         self.obj = Objective()
#
#     # 初始化种群
#     def init_population(self):
#         with tqdm(total=POP_SIZE) as pbar:
#             pbar.set_description('种群初始化进度')
#             # 计算任务队列的长度
#             size = len(self.TaskList)
#             # 随机生成一组任务顺序和机器分配
#             while len(self.population) < self.POP_SIZE:
#                 order = random.sample(range(1, size + 1), size)
#                 machine = [-1] * size
#                 # 根据order队列依次分配作业设备
#                 for elem in order:
#                     task = self.TaskList[elem - 1]
#                     if task['StartPosition'][1] <= 3 or task['EndPosition'][1] <= 3:
#                         machine[order.index(elem)] = 1
#                     elif task['StartPosition'][1] >= 13 or task['EndPosition'][1] >= 13:
#                         machine[order.index(elem)] = 0
#                     else:
#                         machine[order.index(elem)] = random.randint(0, 1)
#                 DNA = order + machine
#                 new_individual = Individuals(DNA=DNA)
#                 if new_individual.DNAFeasibility():
#                     fitness = self.fitness_func(DNA)
#                     if fitness != 10e8:
#                         pbar.update(1)
#                 else:
#                     del new_individual
#                     continue
#
#     # 适应度评估
#     def fitness_evaluation(self):
#         for elem in self.population:
#             elem.fitness = self.fitness_func(elem.DNA)
#             if elem.fitness < self.best_fitness:
#                 self.best = elem
#                 self.best_fitness = elem.fitness
#
#     # 适应度函数
#     def fitness_func(self, DNA: list):
#         # DNA解码
#         size = len(DNA) // 2
#         order = DNA[:size]
#         machine = DNA[size:]
#         # 根据任务顺序和机器分配，获得TaskList中对应任务和机器
#         CraneTask = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 1]
#         ReachStackerTask = [TaskList[order[i] - 1] for i in range(size) if machine[i] == 0]
#         try:
#             fitness = self.obj.evaluate(copy.deepcopy(CraneTask), copy.deepcopy(ReachStackerTask))
#         except simpy.Interrupt:
#             fitness = 10e8
#         if fitness == 10e8:
#             pass
#         if not START_EVOLUTION and fitness != 10e8:
#             new_individual = Individuals(DNA=DNA)
#             new_individual.fitness = fitness
#             self.population.append(new_individual)
#         if START_EVOLUTION and fitness != 10e8:
#             new_individual = Individuals(DNA=DNA)
#             new_individual.fitness = fitness
#             self.child.append(new_individual)
#         if fitness < self.best_fitness:
#             self.best = Individuals(DNA=DNA)
#             self.best.fitness = fitness
#             self.best_fitness = fitness
#         return fitness
#
#     # 轮盘赌选择
#     def roulette_wheel_select(self):
#         # 计算适应度总和
#         fitness_sum = sum([(1 / elem.fitness) for elem in self.population])
#         # 计算适应度比例
#         fitness_ratio = [(1 / elem.fitness) / fitness_sum for elem in self.population]
#         # 计算适应度累积比例
#         fitness_cumsum = np.cumsum(fitness_ratio)
#         # 生成随机数
#         rand = random.random()
#         # 选择一个个体
#         for i in range(self.POP_SIZE):
#             if rand < fitness_cumsum[i]:
#                 return self.population[i]
#
#     # 锦标赛选择
#     def tournament_select(self, n=3):
#         # 在种群中随机选择n个个体
#         selected_individuals = random.sample(self.population, k=n)
#         # 选择其中适应度最高的个体(时间最短)
#         selected_individuals.sort(key=lambda x: x.fitness, reverse=False)
#         return selected_individuals[0]
#
#     # 单点交叉
#     def single_point_crossover(self, parent1, parent2):
#         # 生成交叉点
#         cross_point = random.randint(10, len(parent1.DNA) - 1)
#         # 生成子代
#         child1 = Individuals(DNA=parent1.DNA[:cross_point] + parent2.DNA[cross_point:])
#         child2 = Individuals(DNA=parent2.DNA[:cross_point] + parent1.DNA[cross_point:])
#         return child1, child2
#
#     # 顺序交叉(不改变分配方案，只改变作业顺序)
#     @para_check
#     def order_crossover(self, parent1, parent2, typed):
#         # 生成交叉点
#         size = len(parent1.DNA) // 2
#         parent1_DNA = parent1.DNA
#         parent1_Order = parent1_DNA[:size]
#         parent1_Machine = parent1_DNA[size:]
#
#         parent2_DNA = parent2.DNA
#         parent2_Order = parent2_DNA[:size]
#         parent2_Machine = parent2_DNA[size:]
#
#         cross_point_low = random.randint(0, size - 2)
#         cross_point_high = random.randint(cross_point_low + 1, size - 1)
#
#         # 生成子代
#         child_Order = [-1] * size
#         child_Machine = [-1] * size
#
#         # 截取父本1的顺序片段DNA
#         parent1_Order_slice = parent1_Order[cross_point_low:cross_point_high]
#         # 截取父本1的机器片段DNA
#         parent1_Machine_slice = parent1_Machine[cross_point_low:cross_point_high]
#         # 获取父本1对应的DNA索引
#         parent1_Order_index = [parent1_Order.index(elem) for elem in parent1_Order_slice]
#         # 获取父本2对应的DNA索引
#         parent2_Order_index = [parent2_Order.index(elem) for elem in parent1_Order_slice]
#         # 根据父本2的DNA索引删除父本2的DNA
#         for elem in parent2_Order_index:
#             parent2_Order[elem] = -1
#             parent2_Machine[elem] = -1
#         parent2_Order = [elem for elem in parent2_Order if elem != -1]
#         parent2_Machine = [elem for elem in parent2_Machine if elem != -1]
#         # 将父本1的DNA按照对应位置插入子代
#         for i in parent1_Order_index:
#             child_Order[i] = parent1_Order_slice.pop(0)
#             child_Machine[i] = parent1_Machine_slice.pop(0)
#         # 将父本2的剩余DNA按照对应位置插入子代
#         for i in range(size):
#             if child_Order[i] == -1:
#                 child_Order[i] = parent2_Order.pop()
#                 child_Machine[i] = parent2_Machine.pop()
#         return Individuals(DNA=child_Order + child_Machine)
#
#     # 单点变异
#     @para_check
#     def single_point_mutate(self, parent, typed):
#         size = len(parent.DNA) // 2
#         parent1_DNA = parent.DNA
#         parent1_Order = parent1_DNA[:size]
#         parent1_Machine = parent1_DNA[size:]
#         # 分配方案上修改单点进行变异
#         if typed == 'machine':
#             # 生成变异点
#             mutate_point = random.randint(0, size - 1)
#             # 反转变异点的值
#             parent1_Machine[mutate_point] = 1 - parent1_Machine[mutate_point]
#             child = Individuals(DNA=parent1_Order + parent1_Machine)
#             return child
#         # 作业顺序上进行2-opt变异
#         if typed == 'order':
#             single_point_low = random.randint(0, size - 2)
#             single_point_high = random.randint(single_point_low + 1, size - 1)
#             # 2-opt变异
#             parent1_Order[single_point_low], parent1_Order[single_point_high] = parent1_Order[single_point_high], \
#                 parent1_Order[single_point_low]
#             child = Individuals(DNA=parent1_Order + parent1_Machine)
#             return child
#
#     # 进化
#     def elite_selection(self, n=ELITE_RETAIN):
#         # 选择适应度最高的n个个体
#         self.population.sort(key=lambda x: x.fitness, reverse=False)
#         elite = self.population[:n]
#         for elem in elite:
#             self.child.append(copy.deepcopy(elem))


"""-------------------------------------适应度函数类定义-------------------------------------"""


class Objective:
    # 状态定义：
    # -2. 无任务空闲状态 / 无法作业状态
    # -1. 避让状态
    # 0. 有任务空闲状态
    # 1. 空载移动状态
    # 2. 抓取状态
    # 3. 重载移动状态
    # 4. 放置状态
    # 5. 换线状态
    PRIORITY = [-2, -1, 0, 5, 1, 3, 2, 4]
    SafetyDistance = 1
    # 环境定义
    env = simpy.Environment()
    # 全局事件定义
    SimulationStopEvent = env.event()
    ShaduleEvent = env.event()
    CraneTaskQueue = []
    ReachStackerTaskQueue = []

    # 轨道吊任务队列
    # CraneTaskQueue =[{'StartPosition': [2,7,2], 'EndPosition': [15,7,1]}]
    # ReachStackerTaskQueue =[{'StartPosition': [2,8,1], 'EndPosition': [15,9,1]}]
    def __init__(self):
        ContainerLocationTable = pd.read_excel("箱位状态表(20240325目前可用).xlsx")
        for index, row in ContainerLocationTable.iterrows():
            Objective.ContainerLocation(stack=row["栈位"], bay=row["贝位"], level=row["层位"], state=row["占用状态"],
                                        Locationtype=row["位置类型"])
        self.ContainerLocationCopy = copy.deepcopy(Objective.ContainerLocation.ContainerList)

    def evaluate(self, CraneTaskQueue, ReachStackerTaskQueue):
        Objective.env = simpy.Environment()
        self.ReachStacker = Objective.ReachStacker(Objective.env, "ReachStacker", self)
        self.Crane = Objective.Crane(Objective.env, "Crane", self)
        self.ControllStation = Objective.ControllStation(Objective.env, self)
        Objective.ContainerLocation.ContainerList = copy.deepcopy(self.ContainerLocationCopy)
        Objective.CraneTaskQueue = CraneTaskQueue
        Objective.ReachStackerTaskQueue = ReachStackerTaskQueue
        Objective.SimulationStopEvent = Objective.env.event()
        Objective.ShaduleEvent = Objective.env.event()
        self.env.process(self.CheckDeviceDeadLock())
        Objective.env.run(Objective.SimulationStopEvent)
        Crane_PosRegister = self.Crane.PosRegister
        ReachStacker_PosRegister = self.ReachStacker.PosRegister
        print(self.ReachStacker.PosRegister)
        del self.ReachStacker
        del self.Crane
        del self.ControllStation
        return Objective.env.now,Crane_PosRegister,ReachStacker_PosRegister

    "----------------------------工具函数-----------------------------"

    def Get_MoveRange(*args: list) -> np.ndarray:
        if len(args) == 1:
            Position = args[0]
            return np.arange(Position[0] - Objective.SafetyDistance, Position[0] + 1 + Objective.SafetyDistance)
        if len(args) == 2:
            StartPoint = args[0]
            EndPoint = args[1]
            # 判断起点和终点的位置关系
            if StartPoint[0] == EndPoint[0]:
                return np.arange(StartPoint[0] - Objective.SafetyDistance, EndPoint[0] + 1 + Objective.SafetyDistance)
            elif StartPoint[0] < EndPoint[0]:
                return np.arange(StartPoint[0] - Objective.SafetyDistance, EndPoint[0] + 1 + Objective.SafetyDistance)
            else:
                return np.arange(StartPoint[0] + Objective.SafetyDistance, EndPoint[0] - 1 - Objective.SafetyDistance,
                                 -1)

    # 设备死锁判断
    def CheckDeviceDeadLock(self):
        while True:
            if self.ReachStacker.PosRegister == [] or self.Crane.PosRegister == []:
                yield self.env.timeout(10)
                continue
            # 查询正面吊最后记录信息
            ReachStackerLastInfo = self.ReachStacker.PosRegister[-1]
            # 获取正面吊最后的作业位置
            ReachStackerLastPosition = ReachStackerLastInfo[0:2]
            # 查询正面吊持续最后作业位置的时间
            end = ReachStackerLastInfo[3]
            start = 0
            for elem in self.ReachStacker.PosRegister[::-1]:
                if elem[0:2] != ReachStackerLastPosition:
                    start = elem[3]
                    break
            # 计算正面吊持续最后作业状态的时间
            ReachStackerLockTime = end - start
            # 查询轨道吊最后记录信息
            CraneLastInfo = self.Crane.PosRegister[-1]
            # 获取轨道吊最后的作业状态
            CraneLastPosition = CraneLastInfo[0:2]
            # 查询轨道吊持续最后作业状态的时间
            end = CraneLastInfo[3]
            start = 0
            for elem in self.Crane.PosRegister[::-1]:
                if elem[0:2] != CraneLastPosition:
                    start = elem[3]
                    break
            # 计算轨道吊持续最后作业状态的时间
            CraneLockTime = end - start
            if ReachStackerLockTime > 100 and CraneLockTime > 100:
                # 判断设备死锁，抛出异常
                raise simpy.Interrupt("设备死锁")
            else:
                yield self.env.timeout(10)
                continue

    "----------------------------枚举类-----------------------------"

    class WorkLinePos(enum.Enum):
        Up = 1
        Down = 2

    "----------------------------集装箱箱位类-----------------------------"

    class ContainerLocation:
        ContainerList = []
        ContainerListCopy = []

        def __init__(self, bay, stack, level, state, Locationtype):
            self.bay = bay  # 贝位
            self.level = level  # 层位
            self.stack = stack  # 栈位
            self.state = state  # 集装箱箱位状态: 放置货物 1 没有货物 0
            self.Locationtype = Locationtype  # 箱位类型: 0 普通箱位 1 道路箱位
            Objective.ContainerLocation.ContainerList.append(self)

        # 根据箱位号查询箱位对象列表
        @classmethod
        def FindContainerLocation(cls, bay, stack, level):
            return [x for x in cls.ContainerList if (x.stack == stack and x.level == level and x.bay == bay)]

        @classmethod
        def ContainerLocationListSave(cls):
            cls.ContainerListCopy.clear()
            cls.ContainerListCopy = copy.deepcopy(cls.ContainerList)
            return True

        @classmethod
        def ContainerLocationListRecover(cls):
            cls.ContainerList.clear()
            cls.ContainerList = copy.deepcopy(cls.ContainerListCopy)
            return True

        # 判断集装箱位置是否可抓取
        def CheckContainerLocationPick(self):
            if self.Locationtype == 1:
                return True
            # 如果当前货位上有货物，进一步判断
            if self.state == 1:
                # 如果当前货位处于二层，可以抓取
                if self.level == 2:
                    return True
                # 如果当前货位处于一层，判断是否为列车箱位
                if self.level == 1 and self.Locationtype == 2:
                    return True
                elif self.level == 1 and self.Locationtype != 2:
                    try:
                        # 获取二层货位对象
                        ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(self.bay,
                                                                                                    self.stack,
                                                                                                    self.level + 1).pop()
                    except IndexError:
                        return True
                    # 如果二层货位上有货物不可抓取，否则可以抓取
                    if ContainerLocationSelect.state == 1:
                        return False
                    else:
                        return True
            # 如果当前货位上没有货物，不可抓取
            else:
                return False

        def CheckContainerLocationPut(self):
            if self.Locationtype == 1:
                return True
            # 如果当前货位上没有货物，进一步判断
            if self.state == 0:
                # 如果当前货位处于一层，可以放置
                if self.level == 1:
                    return True
                # 如果当前货位处于二层，判断一层是否有货物
                elif self.level == 2:
                    # 获取二层货位对象
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(self.bay, self.stack,
                                                                                                self.level - 1).pop()
                    # 如果一层货位上有货物则可以放置，否则不可放置
                    if ContainerLocationSelect.state == 1:
                        return True
                    else:
                        return False
            # 如果当前货位上有货物，不可放置
            else:
                return False

        # 计算正面吊可以停靠的位置
        def DockingLocationSearch(self):
            TargetBay = self.bay
            # 获得目标位置的贝位和栈位
            TargetStack = self.stack
            # 栈位超出范围，无解，给出异常
            assert 3 < TargetStack < 15
            # 通道规则
            if TargetStack == 4:
                return [None, [TargetBay, 5]]
            if TargetStack == 5:
                return [None, [TargetBay, 6]]
            if TargetStack == 6:
                return [None, [TargetBay, 5]]
            if TargetStack == 13:
                return [[TargetBay, 14], None]
            if TargetStack == 14:
                return [[TargetBay, 13], None]
            MovePathUp = []
            MovePathDown = []
            CheckStack = TargetStack
            while True:
                # 向上侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                CheckStack += 1
                ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                            1).pop()
                if ContainerLocationSelect.Locationtype == 1:
                    MovePathUp.append(CheckStack)
                    break
                # 若不为道路，则检查当前位置一层是否有集装箱，若有则不能成为可用路径
                else:
                    if ContainerLocationSelect.state == 0:
                        MovePathUp.append(CheckStack)
                        continue
                    else:
                        # 判断是否为目标栈位的邻接栈位，若是则检查二层是否有集装箱，若没有则继续搜索，否则直接退出
                        if abs(CheckStack - TargetStack) == 1:
                            if Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                 2).pop().state <= \
                                    Objective.ContainerLocation.FindContainerLocation(TargetBay, TargetStack,
                                                                                      2).pop().state:
                                continue
                            else:
                                MovePathUp.clear()
                                break
                        else:
                            MovePathUp.clear()
                            break
            CheckStack = TargetStack
            while True:
                # 向下侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                CheckStack -= 1
                ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                            1).pop()
                if ContainerLocationSelect.Locationtype == 1:
                    MovePathDown.append(CheckStack)
                    break
                # 若不为道路，则检查当前位置一层是否有集装箱，若有则不能成为可用路径
                else:
                    if ContainerLocationSelect.state == 0:
                        MovePathDown.append(CheckStack)
                        continue
                    else:
                        # 判断是否为目标栈位的邻接栈位，若是则检查二层是否有集装箱，若没有则继续搜索，否则直接退出
                        if abs(CheckStack - TargetStack) == 1:
                            if Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                 2).pop().state <= \
                                    Objective.ContainerLocation.FindContainerLocation(TargetBay, TargetStack,
                                                                                      2).pop().state:
                                continue
                            else:
                                MovePathDown.clear()
                                break
                        else:
                            MovePathDown.clear()
                            break
            if len(MovePathUp) != 0 or len(MovePathDown) != 0:
                if len(MovePathUp) != 0:
                    MovePathUp = np.array(MovePathUp)
                    DockingLocationUp = [TargetBay, np.min(MovePathUp)]
                else:
                    DockingLocationUp = None
                if len(MovePathDown) != 0:
                    MovePathDown = np.array(MovePathDown)
                    DockingLocationDown = [TargetBay, np.max(MovePathDown)]
                else:
                    DockingLocationDown = None
                return [DockingLocationUp, DockingLocationDown]
            else:
                return False

        def PlacingFeasibilityQueries(self):
            TargetBay = self.bay
            TargetStack = self.stack
            if TargetStack < 7 or TargetStack > 12:
                return True
            else:
                # 初始化集装箱位置列表
                ContainerLocationInit = []
                for stack in range(7, 13):
                    ContainerLocationInit.append(
                        Objective.ContainerLocation.FindContainerLocation(TargetBay, stack, 1).pop())
                # 记录活动集装箱位置（即正面吊所涉及的所有集装箱位置）
                ActiveContainerLocation = []
                for item in Objective.ReachStackerTaskQueue:
                    for key, value in item.items():
                        selectselectContainerLocation = Objective.ContainerLocation.FindContainerLocation(value[0],
                                                                                                          value[1],
                                                                                                          1).pop()
                        if (
                                selectselectContainerLocation.state == 1 and key == "StartPosition") or key == "EndPosition":
                            ActiveContainerLocation.append(
                                Objective.ContainerLocation.FindContainerLocation(value[0], value[1], 1).pop())
                        else:
                            continue
                # 删除活动集装箱位置，剩下的即为固定集装箱位置（即正面吊不涉及的集装箱位置）
                for item in ActiveContainerLocation:
                    try:
                        ContainerLocationInit.remove(item)
                    except ValueError:
                        continue
                FixedContainerPosition = ContainerLocationInit.copy()
                TargetBay = self.bay
                TargetStack = self.stack
                CheckStack = TargetStack
                FixContainerexistFlag = False
                ActiveContainerexistFlag = False
                while True:
                    # 向上侧查找，先判断是否为道路,若为道路,则将检查位置加入路径，退出
                    CheckStack += 1
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                                1).pop()
                    if ContainerLocationSelect.Locationtype == 1:
                        break
                    else:
                        if ContainerLocationSelect in FixedContainerPosition:
                            FixContainerexistFlag = True
                        if ContainerLocationSelect in ActiveContainerLocation:
                            ActiveContainerexistFlag = True
                if FixContainerexistFlag == True and ActiveContainerexistFlag == True:
                    return False
                else:
                    pass
                FixContainerexistFlag = False
                ActiveContainerexistFlag = False
                CheckStack = TargetStack
                while True:
                    # 向下侧查找，先判断是否为道路,若为道路则退出
                    CheckStack -= 1
                    ContainerLocationSelect = Objective.ContainerLocation.FindContainerLocation(TargetBay, CheckStack,
                                                                                                1).pop()
                    if ContainerLocationSelect.Locationtype == 1:
                        break
                    else:
                        if ContainerLocationSelect in FixedContainerPosition:
                            FixContainerexistFlag = True
                        if ContainerLocationSelect in ActiveContainerLocation:
                            ActiveContainerexistFlag = True
                if FixContainerexistFlag == True and ActiveContainerexistFlag == True:
                    return False
                else:
                    return True

    "----------------------------调度控制器类-----------------------------"

    class ControllStation:
        DataStack = []

        def __init__(self, env, obj):
            self.env = env
            self.env.process(self.main())
            self.env.process(self.running())
            self.ShaduleDevice = []
            self.obj = obj

        def running(self):
            yield Objective.SimulationStopEvent
            return True

        # 作业调度函数
        def Schedule(self, Device):
            """-----------------------------------标志位---------------------------------------"""
            # 优先级标志位
            PriorityFlag = False
            # 作业交叉标志位
            CrossFlag = False
            # 主调度设备可作业标志位
            MainShaduleDeviceWorkFeasibility = True
            """-----------------------------------中间变量--------------------------------------"""
            # 调度数据栈
            ScheduleDataStack = []

            # 指定主调度设备与被调度设备
            MainShaduleDevice = Device
            BeShaduleDevice = self.obj.ReachStacker if Device == self.obj.Crane else self.obj.Crane
            # 获取主调度设备基本作业信息
            MainShaduleDeviceStateCode = MainShaduleDevice.StateCode
            MainShaduleDeviceCurrentPos = MainShaduleDevice.CurrentPos
            MainShaduleDeviceCurrentTask = MainShaduleDevice.CurrentTask
            MainShaduleDeviceTargetPos = MainShaduleDevice.TargetPos
            MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDeviceStateCode)
            # 获取被调度设备基本作业信息
            BeShaduleDeviceStateCode = BeShaduleDevice.StateCode
            BeShaduleDeviceCurrentPos = BeShaduleDevice.CurrentPos
            BeShaduleDeviceCurrentTask = BeShaduleDevice.CurrentTask
            BeShaduleDeviceTargetPos = BeShaduleDevice.TargetPos
            BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDeviceStateCode)

            """----------------------------------------作业可行性判断----------------------------------"""
            # 判断主调度设备是否为正面吊
            if MainShaduleDevice is self.obj.ReachStacker:
                # 判断正面吊作业的作业状态
                if not MainShaduleDevice.LoadOn:
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    if MainShaduleDevice.TargetPos[1] in [1, 2, 3]:
                        raise simpy.Interrupt("分配错误")
                    # 判断该位置是否能抓取
                    PickUPContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDevice.TargetPos[0],
                        MainShaduleDevice.TargetPos[1],
                        MainShaduleDevice.TargetPos[2]).pop()

                    # 若该位置不能抓取，等待
                    if not PickUPContainerLocation.CheckContainerLocationPick():
                        # 主调度作业设备不可作业
                        MainShaduleDevice.StateCode = -1
                        MainShaduleDevice.AvoidancePos = MainShaduleDevice.CurrentPos
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 主调度作业设备可作业
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
                else:
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    if MainShaduleDevice.TargetPos[1] in [1, 2, 3]:
                        raise simpy.Interrupt("分配错误")
                    # 判断该位置是否能放置
                    PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDevice.TargetPos[0],
                        MainShaduleDevice.TargetPos[1],
                        MainShaduleDevice.TargetPos[2]).pop()
                    # 若该位置不能放置，等待
                    if not PutContainerLocation.CheckContainerLocationPut():
                        # 主调度作业设备不可作业
                        MainShaduleDevice.StateCode = -1
                        MainShaduleDevice.AvoidancePos = MainShaduleDevice.CurrentPos
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 主调度作业设备可作业
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
                # 获得正面吊的停靠位置
                DockingLocation = Objective.ContainerLocation.FindContainerLocation(MainShaduleDevice.TargetPos[0],
                                                                                    MainShaduleDevice.TargetPos[1],
                                                                                    MainShaduleDevice.TargetPos[
                                                                                        2]).pop().DockingLocationSearch()
                # 无停靠位置，等待or避让
                if DockingLocation is False:
                    # 主调度作业设备不可作业
                    MainShaduleDevice.StateCode = -1
                    MainShaduleDevice.AvoidancePos = MainShaduleDevice.CurrentPos
                    MainShaduleDeviceWorkFeasibility = False
                else:
                    # 主调度作业设备可作业
                    MainShaduleDevice.StateCode = 0
                    MainShaduleDeviceWorkFeasibility = True

                # 有停靠位置
                if MainShaduleDevice.Worklinepos == Objective.WorkLinePos.Down and DockingLocation is not False:
                    DockingLocation_ = DockingLocation[1]
                    if DockingLocation_ is None:
                        Objective.ControllStation.DataStack.append(DockingLocation[0])
                        MainShaduleDevice.ReplaceWorkLineEvent.succeed()
                        MainShaduleDevice.ReplaceWorkLineEvent = MainShaduleDevice.env.event()
                        return True
                    else:
                        MainShaduleDevice.TargetPos = DockingLocation_
                        MainShaduleDeviceTargetPos = DockingLocation_

                elif MainShaduleDevice.Worklinepos == Objective.WorkLinePos.Up and DockingLocation is not False:
                    DockingLocation_ = DockingLocation[0]
                    if DockingLocation_ is None:
                        Objective.ControllStation.DataStack.append(DockingLocation[1])
                        MainShaduleDevice.ReplaceWorkLineEvent.succeed()
                        MainShaduleDevice.ReplaceWorkLineEvent = MainShaduleDevice.env.event()
                        return True
                    else:
                        MainShaduleDevice.TargetPos = DockingLocation_
                        MainShaduleDeviceTargetPos = DockingLocation_
            # 判断主调度设备是否为轨道吊
            else:
                # 轨道吊是否处于空载作业状态
                if not MainShaduleDevice.LoadOn:
                    MainShaduleDeviceTargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["StartPosition"]
                    if MainShaduleDeviceTargetPos[1] in [13, 14]:
                        raise simpy.Interrupt("分配错误")
                    # 判断该位置是否能抓取
                    PickUPContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDeviceTargetPos[0],
                        MainShaduleDeviceTargetPos[1],
                        MainShaduleDeviceTargetPos[
                            2]).pop()
                    # 若该位置不能抓取，等待
                    if not PickUPContainerLocation.CheckContainerLocationPick():
                        # 将主调度设备调度状态改为避让状态
                        MainShaduleDevice.StateCode = -1
                        MainShaduleDevice.AvoidancePos = MainShaduleDevice.CurrentPos
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 恢复主调度设备作业状态
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True

                else:
                    MainShaduleDeviceTargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    MainShaduleDevice.TargetPos = MainShaduleDevice.CurrentTask["EndPosition"]
                    if MainShaduleDeviceTargetPos[1] in [13, 14]:
                        raise simpy.Interrupt("分配错误")
                    # 判断该位置是否能放置
                    PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                        MainShaduleDeviceTargetPos[0],
                        MainShaduleDeviceTargetPos[1],
                        MainShaduleDeviceTargetPos[2]).pop()

                    if not PutContainerLocation.PlacingFeasibilityQueries() or not PutContainerLocation.CheckContainerLocationPut():
                        # 将主调度设备调度状态改为避让状态
                        MainShaduleDevice.StateCode = -1
                        MainShaduleDevice.AvoidancePos = MainShaduleDevice.CurrentPos
                        MainShaduleDeviceWorkFeasibility = False
                    else:
                        # 恢复主调度设备作业状态
                        MainShaduleDevice.StateCode = 0
                        MainShaduleDeviceWorkFeasibility = True
            # 获取主调度设备的预计作业区间
            MainShaduleDeviceMoveRange = None
            if MainShaduleDevice.StateCode == 0:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos,
                                                                     MainShaduleDevice.TargetPos)
            elif MainShaduleDevice.StateCode == -1:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos,
                                                                     MainShaduleDevice.AvoidancePos)
            elif MainShaduleDevice.StateCode == -2:
                MainShaduleDeviceMoveRange = Objective.Get_MoveRange(MainShaduleDevice.CurrentPos)
            # 获取被调度设备的正在作业区间
            BeShaduleDeviceMoveRange = None
            if BeShaduleDevice.StateCode == 0 or BeShaduleDevice.StateCode == 1 or BeShaduleDevice.StateCode == 3 \
                    or BeShaduleDevice.StateCode == 5:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos,
                                                                   BeShaduleDevice.TargetPos)
            elif BeShaduleDevice.StateCode == 2 or BeShaduleDevice.StateCode == 4 or BeShaduleDevice.StateCode == -2:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos)
            elif BeShaduleDeviceStateCode == -1:
                BeShaduleDeviceMoveRange = Objective.Get_MoveRange(BeShaduleDevice.CurrentPos,
                                                                   BeShaduleDevice.AvoidancePos)
            min_val = 0
            max_val = 65
            # 判断主调度设备作业优先级是否大于被调度设备
            if MainShaduleDevice.StateCode == 0 and MainShaduleDevice.LoadOn == True:
                # 获得当前贝位与目标贝位的距离差并归一化
                Distance = abs(MainShaduleDevice.CurrentPos[0] - MainShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDevice.StateCode) + 0.5 + alpha
            else:
                Distance = abs(MainShaduleDevice.CurrentPos[0] - MainShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                MainShaduleDevicePriority = Objective.PRIORITY.index(MainShaduleDevice.StateCode) + alpha
            if BeShaduleDevice.StateCode == 0 and BeShaduleDevice.LoadOn == True:
                Distance = abs(BeShaduleDevice.CurrentPos[0] - BeShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDevice.StateCode) + 0.5 + alpha
            else:
                Distance = abs(BeShaduleDevice.CurrentPos[0] - BeShaduleDevice.TargetPos[0])
                alpha = 0.5 - (0.5 * (Distance - min_val) / (max_val - min_val))
                BeShaduleDevicePriority = Objective.PRIORITY.index(BeShaduleDevice.StateCode) + alpha
            if MainShaduleDevicePriority > BeShaduleDevicePriority:
                PriorityFlag = True
            elif MainShaduleDevicePriority == BeShaduleDevicePriority and MainShaduleDevice == self.obj.Crane:
                PriorityFlag = True
            else:
                PriorityFlag = False
            # 判断主调度设备与被调度设备是否交叉
            if self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down and len(
                    np.intersect1d(MainShaduleDeviceMoveRange, BeShaduleDeviceMoveRange)) > 1:
                CrossFlag = True
            else:
                CrossFlag = False

            """---------------------------------------执行作业-------------------------------------------------------"""
            # if MainShaduleDeviceWorkFeasibility is False:
            #     MainShaduleDevice.WaitEvent.succeed()
            #     return True
            # 主调度设备优先级高且两设备不存在路径重叠情形，主调度设备直接作业
            if PriorityFlag == True and CrossFlag == False:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            # 主调度设备优先级低且两设备不存在路径重叠情形，主调度设备直接作业
            if PriorityFlag == False and CrossFlag == False and MainShaduleDeviceWorkFeasibility is True:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            if PriorityFlag == False and CrossFlag == False and MainShaduleDeviceWorkFeasibility is False:
                MainShaduleDevice.WaitEvent.succeed()
                MainShaduleDevice.WaitEvent = Objective.env.event()
            # 主调度设备优先级高且两设备存在路径重叠情形，被调度设备作业中断且进行避让，主调度设备优先作业
            if PriorityFlag == True and CrossFlag == True and BeShaduleDevice.DeviceLock == True:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
            elif PriorityFlag == True and CrossFlag == True and BeShaduleDevice.DeviceLock == False:
                MainShaduleDevice.MoveEvent.succeed()
                MainShaduleDevice.MoveEvent = Objective.env.event()
                # 判断被动调度设备是否需要避让，即被动调度设备当前位置是否在主调度设备的预计作业区间内
                if BeShaduleDevice.CurrentPos[0] in MainShaduleDeviceMoveRange:
                    if BeShaduleDevice == self.obj.Crane:
                        Avoidanceloc = [np.max(MainShaduleDeviceMoveRange) + 1, BeShaduleDevice.CurrentPos[1]]
                    else:
                        Avoidanceloc = [np.min(MainShaduleDeviceMoveRange) - 1, BeShaduleDevice.CurrentPos[1]]
                    Objective.ControllStation.Avoidance(BeShaduleDevice, Avoidanceloc)
                else:
                    Objective.ControllStation.Wait(BeShaduleDevice)

            # 主调度设备优先级低且两设备存在路径重叠情形，判断主调度设备是否碍事，若碍事则避让，否则原地等待
            if PriorityFlag == False and CrossFlag == True and MainShaduleDevice.DeviceLock == True:
                pass
            elif PriorityFlag == False and CrossFlag == True and MainShaduleDevice.DeviceLock == False:
                CrossRange = np.intersect1d(MainShaduleDeviceMoveRange, BeShaduleDeviceMoveRange)
                if MainShaduleDevice.CurrentPos[0] in CrossRange:
                    if MainShaduleDevice == self.obj.Crane:
                        Avoidanceloc = [np.max(BeShaduleDeviceMoveRange) + 1, MainShaduleDevice.CurrentPos[1]]
                    else:
                        Avoidanceloc = [np.min(BeShaduleDeviceMoveRange) - 1, MainShaduleDevice.CurrentPos[1]]
                    Objective.ControllStation.Avoidance(MainShaduleDevice, Avoidanceloc)
                else:
                    Objective.ControllStation.Wait(MainShaduleDevice)

        @staticmethod
        def Avoidance(obj, loc):
            "避让作业"
            obj.InterruptWorkEvent.succeed()
            obj.InterruptWorkEvent = Objective.env.event()
            # 避让到指定位置
            obj.AvoidancePos = loc
            obj.AvoidanceEvent.succeed()
            obj.AvoidanceEvent = Objective.env.event()
            obj.DeviceLock = True
            return True

        @staticmethod
        def Wait(obj):
            "等待作业"
            obj.InterruptWorkEvent.succeed()
            obj.InterruptWorkEvent = Objective.env.event()
            obj.WaitEvent.succeed()
            obj.WaitEvent = Objective.env.event()
            obj.DeviceLock = True
            return True

        def main(self):
            CraneShaduleCount = 1
            ReachStackerShaduleCount = 1
            while True:
                "----------------------------任务分配-----------------------------"
                # 获取轨道吊相关信息
                CraneInfo = self.obj.Crane.GetInfo("Crane")
                # 获取正面吊相关信息
                ReachStackerInfo = self.obj.ReachStacker.GetInfo("ReachStacker")
                if CraneInfo["CurrentTask"] == {} and Objective.CraneTaskQueue != [] and CraneInfo["StateCode"] == -2:
                    # Crane.CurrentTask = CraneTaskQueue.pop(0)
                    self.obj.Crane.CurrentTask = Objective.CraneTaskQueue[0]
                    self.obj.Crane.StateCode = 0
                    CraneShaduleCount += 1
                    self.ShaduleDevice.append(self.obj.Crane)
                elif CraneInfo["CurrentTask"] == {} and Objective.CraneTaskQueue == []:
                    self.obj.Crane.StateCode = -2
                if ReachStackerInfo["CurrentTask"] == {} and Objective.ReachStackerTaskQueue != [] and ReachStackerInfo[
                    "StateCode"] == -2:
                    # ReachStacker.CurrentTask = ReachStackerTaskQueue.pop(0)
                    self.obj.ReachStacker.CurrentTask = Objective.ReachStackerTaskQueue[0]
                    self.obj.ReachStacker.StateCode = 0
                    ReachStackerShaduleCount += 1
                    self.ShaduleDevice.append(self.obj.ReachStacker)
                elif ReachStackerInfo["CurrentTask"] == {} and Objective.ReachStackerTaskQueue == []:
                    self.obj.ReachStacker.StateCode = -2
                for Device in self.ShaduleDevice:
                    self.Schedule(Device)
                    # print("{}调度，当前设备状态为{}".format(Device.name, Device.StateCode))
                self.ShaduleDevice.clear()
                "----------------------------仿真结束条件-----------------------------"
                # 获取轨道吊相关信息
                CraneInfo = self.obj.Crane.GetInfo("Crane")
                # 获取正面吊相关信息
                ReachStackerInfo = self.obj.ReachStacker.GetInfo("ReachStacker")
                if Objective.CraneTaskQueue == [] and Objective.ReachStackerTaskQueue == [] and CraneInfo[
                    "CurrentTask"] == {} and \
                        ReachStackerInfo["CurrentTask"] == {}:
                    Objective.SimulationStopEvent.succeed()
                    break
                else:
                    yield Objective.ShaduleEvent
                    Device = Objective.ShaduleEvent.value
                    if Device.CurrentTask != {}:
                        self.ShaduleDevice.append(Objective.ShaduleEvent.value)
                    Objective.ShaduleEvent = Objective.env.event()

    "----------------------------正面吊类-----------------------------"

    class ReachStacker(simpy.Resource):
        ReachtSackerName = dict()

        def __init__(self, env, name, obj):
            super().__init__(env)
            self.name = name
            self.env = env
            self.CurrentTask = {}  # 记录当前作业的任务
            self.CurrentPos = [18, 6]  # 记录正面吊当前位置
            self.AvoidancePos = []  # 记录避让位置
            self.StateCode = -2
            self.GANTRY_SPEED = 1.5  # 移动一个贝位所需要的时间
            self.TROLLEY_SPEED = 1.5  # 移动一个栈位所需要的时间
            self.PICK1_TIME = 25  # 抓取一层货物所需时间
            self.PICK2_TIME = 25  # 抓取二层货物所需时间
            self.PUT1_TIME = 25  # 放置一层货物所需时间
            self.PUT2_TIME = 25  # 放置二层货物所需时间
            self.Safe_Distance = Objective.SafetyDistance  # 安全距离
            self.TargetPos = [0, 6]
            self.EnterPos = []
            self.InterruptFlag = False
            self.PosRegister = []  # 记录正面吊大车位置
            self.Worklinepos = Objective.WorkLinePos.Down
            self.DataStack = []
            self.obj = obj
            Objective.ReachStacker.ReachtSackerName[self.name] = self

            "----------------------------标志位定义-----------------------------"
            self.GantryMoveingFlag = False
            self.TrolleyMoveingFlag = False
            self.DeviceLock = False  # 设备锁
            self.LoadOn = False  # 负载状态

            "----------------------------事件定义-----------------------------"
            self.GantryMoveEvent = self.env.event()  # 大车开始移动事件
            self.GantryMoveOverEvent = self.env.event()  # 大车移动结束事件
            self.TrolleyMoveEvent = self.env.event()  # 小车开始移动事件
            self.TrolleyMoveOverEvent = self.env.event()  # 小车移动结束事件
            self.MoveEvent = self.env.event()  # 开始移动事件
            self.PickEvent = self.env.event()  # 抓取事件
            self.PutEvent = self.env.event()  # 放置事件
            self.AvoidanceEvent = self.env.event()  # 避让事件
            self.AvoidanceOverEvent = self.env.event()  # 避让完成事件
            self.WaitEvent = self.env.event()  # 等待事件
            self.ReplaceWorkLineEvent = self.env.event()  # 更换作业线事件
            self.ReplaceWorkLineOverEvent = self.env.event()  # 更换作业线完成事件
            self.InterruptWorkEvent = self.env.event()
            self.GantryMoveProcessInterruptOver = self.env.event()
            self.TrolleyMoveProcessInterruptOver = self.env.event()

            "----------------------------进程定义-----------------------------"
            self.GantryMoveProcess = self.env.process(self.GantryMove())
            self.TrolleyMoveProcess = self.env.process(self.TrolleyMove())
            self.env.process(self.Move())
            self.env.process(self.Pick())
            self.env.process(self.Put())
            self.env.process(self.AvoidanceMove())
            self.env.process(self.Wait())
            self.env.process(self.LocationRecord())
            self.env.process(self.ReplaceWorkLine())
            self.env.process(self.InterruptWork())

        def LocationRecord(self):
            "记录位置"
            while True:
                yield self.env.timeout(1)
                self.PosRegister.append([self.CurrentPos[0], self.CurrentPos[1], self.StateCode, self.env.now])
                if Objective.SimulationStopEvent.processed:
                    break

        @classmethod
        def GetInfo(cls, name):
            reachtSacker = cls.ReachtSackerName[name]
            infodict = dict()
            infodict['StateCode'] = reachtSacker.StateCode
            infodict['CurrentPos'] = reachtSacker.CurrentPos
            infodict['CurrentTask'] = reachtSacker.CurrentTask
            return infodict

        def AvoidanceMove(self):
            while True:
                yield self.AvoidanceEvent
                self.AvoidanceEvent = self.env.event()  # 避让事件重置
                # 保留当前作业状态
                StateCode = self.StateCode
                # 将作业状态设为-1，表示避让
                self.StateCode = -1
                self.TargetPos = self.AvoidancePos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                # 将作业状态设为有任务空闲状态
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def ReplaceWorkLine(self):
            while True:
                yield self.ReplaceWorkLineEvent
                self.ReplaceWorkLineEvent = self.env.event()
                # 将作业状态设为5，表示换线
                self.StateCode = 5
                if self.CurrentPos[1] == 5 or self.CurrentPos[1] == 6:
                    self.TargetPos = [0, 14]
                elif self.CurrentPos[1] == 13 or self.CurrentPos[1] == 14:
                    self.TargetPos = [0, 5]
                self.GantryMoveEvent.succeed()
                yield self.GantryMoveOverEvent
                # 模拟正面吊转弯时间
                yield self.env.timeout(2)
                self.TrolleyMoveEvent.succeed()
                yield self.TrolleyMoveOverEvent
                # 模拟正面吊转弯时间
                yield self.env.timeout(2)
                self.ReplaceWorkLineOverEvent.succeed()
                self.ReplaceWorkLineOverEvent = self.env.event()
                self.TargetPos = Objective.ControllStation.DataStack.pop()
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def InterruptWork(self):
            while True:
                yield self.InterruptWorkEvent
                if self.GantryMoveingFlag:
                    self.GantryMoveProcess.interrupt()
                    yield self.GantryMoveProcessInterruptOver
                    self.GantryMoveProcessInterruptOver = self.env.event()
                if self.TrolleyMoveingFlag:
                    self.TrolleyMoveProcess.interrupt()
                    yield self.TrolleyMoveProcessInterruptOver
                    self.TrolleyMoveProcessInterruptOver = self.env.event()

        def Move(self):
            while True:
                # 抛出开始移动事件，等待事件触发
                yield self.MoveEvent
                # 移动开始事件触发
                # 移动开始事件复位
                self.MoveEvent = self.env.event()
                # 判断当前作业状态，如果作业状态为等待调度状态且没有装载货物，进入下面程序块
                if self.StateCode == 0 and self.LoadOn == False:
                    # 将作业状态设为1，表示正在空载移动
                    self.StateCode = 1
                    # 大车移动开始事件触发
                    self.GantryMoveEvent.succeed()
                    # 大车移动开始事件复位
                    self.GantryMoveEvent = self.env.event()
                    # 等待大车移动结束事件触发
                    yield self.GantryMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        continue
                    # 模拟正面吊转弯时间
                    yield self.env.timeout(2)
                    # 记录进入通道的位置
                    self.EnterPos = copy.deepcopy(self.CurrentPos)
                    # 小车移动开始事件触发
                    self.TrolleyMoveEvent.succeed()
                    # 小车移动开始事件复位
                    self.TrolleyMoveEvent = self.env.event()
                    # 等待小车移动结束事件触发
                    yield self.TrolleyMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        continue
                    # 抓取事件触发
                    self.PickEvent.succeed()
                    # 抓取事件复位
                    self.PickEvent = self.env.event()

                # 判断当前作业状态，如果作业状态为等待调度状态且装载货物，进入下面程序块
                if self.StateCode == 0 and self.LoadOn == True:
                    # 将作业状态设为3，表示正在重载移动
                    self.StateCode = 3
                    # 大车移动开始事件触发
                    self.GantryMoveEvent.succeed()
                    # 大车移动开始事件复位
                    self.GantryMoveEvent = self.env.event()
                    # 等待大车移动结束事件触发
                    yield self.GantryMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    # 记录进入通道的栈位
                    self.EnterPos = copy.deepcopy(self.CurrentPos)
                    # 小车移动开始事件触发
                    self.TrolleyMoveEvent.succeed()
                    # 小车移动开始事件复位
                    self.TrolleyMoveEvent = self.env.event()
                    # 等待小车移动结束事件触发
                    yield self.TrolleyMoveOverEvent
                    # 异常处理，如果遇到中断事件，将中断标志位设为True，跳出循环
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    # 放置事件触发
                    self.PutEvent.succeed()
                    # 放置事件复位
                    self.PutEvent = self.env.event()

        def GantryMove(self):
            while True:
                # 抛出大车移动就绪事件，等待事件触发
                yield self.GantryMoveEvent
                # 大车移动就绪事件复位
                self.GantryMoveEvent = self.env.event()
                while True:
                    self.GantryMoveingFlag = True
                    if self.CurrentPos[0] == self.TargetPos[0]:
                        break
                    else:
                        if self.CurrentPos[0] < self.TargetPos[0]:
                            # 获取轨道吊当前位置
                            CranePos = self.obj.Crane.CurrentPos
                            # 判断安全距离内是否有轨道吊，若是则原地等待，否则移动一个贝位
                            while True:
                                if CranePos[0] == self.CurrentPos[
                                    0] + self.Safe_Distance and self.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            # 移动
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] += 1
                            # print("正面吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            # print("当前时间为{}".format(self.env.now))
                        else:
                            # 获取轨道吊当前位置
                            CranePos = self.obj.Crane.CurrentPos
                            # 判断安全距离内是否有轨道吊，若是则原地等待，否则移动一个贝位
                            while True:
                                if CranePos[0] == self.CurrentPos[
                                    0] - self.Safe_Distance and self.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] -= 1
                            # print("正面吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            # print("当前时间为{}".format(self.env.now))
                self.GantryMoveingFlag = False
                self.GantryMoveOverEvent.succeed()
                self.GantryMoveOverEvent = self.env.event()

        def TrolleyMove(self):
            while True:
                # 抛出小车移动就绪事件，等待事件触发
                yield self.TrolleyMoveEvent
                self.TrolleyMoveEvent = self.env.event()
                while True:
                    self.TrolleyMoveingFlag = True
                    if self.CurrentPos[1] == self.TargetPos[1]:
                        break
                    else:
                        if self.CurrentPos[1] < self.TargetPos[1]:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] += 1
                            if self.CurrentPos[1] in [13, 14]:
                                self.Worklinepos = Objective.WorkLinePos.Up
                            else:
                                self.Worklinepos = Objective.WorkLinePos.Down
                            # print("正面吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            # print("当前时间为{}".format(self.env.now))
                        else:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] -= 1
                            if self.CurrentPos[1] in [13, 14]:
                                self.Worklinepos = Objective.WorkLinePos.Up
                            else:
                                self.Worklinepos = Objective.WorkLinePos.Down
                            # print("正面吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            # print("当前时间为{}".format(self.env.now))
                self.TrolleyMoveingFlag = False
                self.TrolleyMoveOverEvent.succeed()
                self.TrolleyMoveOverEvent = self.env.event()

        def Pick(self):
            while True:
                # 抛出抓取作业事件，等待事件触发
                yield self.PickEvent
                # 抓取作业事件触发
                PickUpContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['StartPosition'][0],
                    self.CurrentTask['StartPosition'][1],
                    self.CurrentTask['StartPosition'][
                        2]).pop()
                # 进入抓取集装箱状态
                self.StateCode = 2
                # 根据抓取集装箱位置，计算抓取时间
                if PickUpContainerLocation.level == 1:
                    Pick_Time = self.PICK1_TIME
                else:
                    Pick_Time = self.PICK2_TIME
                # 模拟抓取时间
                yield self.env.timeout(Pick_Time)
                # 进入运输集装箱状态
                self.LoadOn = True
                # 集装箱箱位状态改变
                PickUpContainerLocation.state = 0
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 3
                # 返回通道入口
                self.TargetPos = self.EnterPos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.TrolleyMoveOverEvent
                # 模拟正面吊转弯时间
                yield self.env.timeout(2)
                # 重置进入通道位置
                self.EnterPos = []
                # 进入等待调度状态
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Put(self):
            while True:
                yield self.PutEvent
                PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['EndPosition'][0],
                    self.CurrentTask['EndPosition'][1],
                    self.CurrentTask['EndPosition'][2]).pop()
                # 进入放置集装箱状态
                self.StateCode = 4
                if PutContainerLocation.level == 1:
                    Put_Time = self.PUT1_TIME
                else:
                    Put_Time = self.PUT2_TIME
                # 模拟放置时间
                yield self.env.timeout(Put_Time)
                # 放置集装箱
                self.LoadOn = False
                # 集装箱箱位状态改变
                PutContainerLocation.state = 1
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 1
                # 返回通道入口
                self.TargetPos = self.EnterPos
                self.GantryMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent
                self.TrolleyMoveEvent.succeed()
                self.TrolleyMoveEvent = self.env.event()
                yield self.TrolleyMoveOverEvent
                self.EnterPos = []
                # 进入空闲状态
                self.StateCode = -2
                # 任务完成，清空任务
                self.CurrentTask.clear()
                self.TargetPos = self.CurrentPos
                Objective.ReachStackerTaskQueue.pop(0)
                # 下一次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Wait(self):
            while True:
                yield self.WaitEvent
                # 重置等待事件
                self.WaitEvent = self.env.event()
                if self.StateCode == -1:
                    self.StateCode = -1
                else:
                    self.StateCode = 0
                # 进入等待状态
                yield self.env.timeout(5)
                # 等待调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

    "----------------------------轨道吊类-----------------------------"

    class Crane(simpy.Resource):
        CraneName = dict()

        def __init__(self, env, name, obj):
            super().__init__(env)
            self.obj = obj
            self.name = name
            self.env = env
            self.CurrentTask = {}  # 记录轨道吊当前任务
            self.CurrentPos = [45, 6]  # 记录轨道吊当前位置
            self.AvoidancePos = []  # 记录轨道吊避让位置
            self.StateCode = -2
            self.GANTRY_SPEED = 6.5  # 移动一个贝位所需要的时间
            self.TROLLEY_SPEED = 2.4  # 移动一个栈位所需要的时间
            self.PICK1_TIME = 80
            self.PICK2_TIME = 70
            self.PUT1_TIME = 80
            self.PUT2_TIME = 70
            self.Safe_Distance = Objective.SafetyDistance  # 安全距离
            self.TargetPos = [18, 0]  # 移动目标位置
            self.PosRegister = []  # 记录轨道吊大车位置
            Objective.Crane.CraneName[self.name] = self

            # 标志位定义
            self.GantryMoveingFlag = False  # 大车正在移动标志位
            self.TrolleyMoveingFlag = False  # 小车正在移动标志位
            self.InterruptFlag = False  # 中断标志位
            self.DeviceLock = False  # 设备锁
            self.LoadOn = False  # 负载状态

            # 事件定义
            self.GantryMoveEvent = self.env.event()  # 大车开始移动事件
            self.GantryMoveOverEvent = self.env.event()  # 大车移动结束事件
            self.TrolleyMoveEvent = self.env.event()  # 小车开始移动事件
            self.TrolleyMoveOverEvent = self.env.event()  # 小车移动结束事件
            self.MoveEvent = self.env.event()  # 移动事件
            self.PickEvent = self.env.event()  # 抓取事件
            self.PutEvent = self.env.event()  # 放置事件
            self.AvoidanceEvent = self.env.event()  # 避让事件
            self.AvoidanceOverEvent = self.env.event()  # 避让完成事件
            self.WaitEvent = self.env.event()  # 等待事件
            self.InterruptWorkEvent = self.env.event()
            self.GantryMoveProcessInterruptOver = self.env.event()
            self.TrolleyMoveProcessInterruptOver = self.env.event()

            # 进程定义
            self.GantryMoveProcess = self.env.process(self.GantryMove())
            self.TrolleyMoveProcess = self.env.process(self.TrolleyMove())
            self.env.process(self.Move())
            self.env.process(self.Pick())
            self.env.process(self.Put())
            self.env.process(self.AvoidanceMove())
            self.env.process(self.Wait())
            self.env.process(self.LocationRecord())
            self.env.process(self.InterruptWork())

        def LocationRecord(self):
            "记录轨道吊位置"
            while True:
                yield self.env.timeout(1)
                self.PosRegister.append([self.CurrentPos[0], self.CurrentPos[1], self.StateCode, self.env.now])
                if Objective.SimulationStopEvent.processed:
                    break

        @classmethod
        def GetInfo(cls, name):
            reachtSacker = cls.CraneName[name]
            infodict = dict()
            infodict['StateCode'] = reachtSacker.StateCode
            infodict['CurrentPos'] = reachtSacker.CurrentPos
            infodict['CurrentTask'] = reachtSacker.CurrentTask
            infodict['TargetPos'] = reachtSacker.TargetPos
            return infodict

        def Move(self):
            while True:
                yield self.MoveEvent
                self.MoveEvent = self.env.event()
                if self.StateCode == 0 and self.LoadOn == False:
                    self.TargetPos = self.CurrentTask['StartPosition']
                    self.StateCode = 1
                    self.GantryMoveEvent.succeed()
                    self.TrolleyMoveEvent.succeed()
                    self.GantryMoveEvent = self.env.event()
                    self.TrolleyMoveEvent = self.env.event()
                    yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    self.PickEvent.succeed()

                if self.StateCode == 0 and self.LoadOn == True:
                    self.TargetPos = self.CurrentTask['EndPosition']
                    self.StateCode = 3
                    self.GantryMoveEvent.succeed()
                    self.TrolleyMoveEvent.succeed()
                    self.GantryMoveEvent = self.env.event()
                    self.TrolleyMoveEvent = self.env.event()
                    yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                    if self.InterruptFlag:
                        self.InterruptFlag = False
                        self.MoveEvent = self.env.event()
                        self.StateCode = 0
                        continue
                    self.PutEvent.succeed()

        def AvoidanceMove(self):
            while True:
                yield self.AvoidanceEvent
                self.AvoidanceEvent = self.env.event()
                # 将作业状态设为-1，表示避让
                self.StateCode = -1
                self.TargetPos = self.AvoidancePos
                self.GantryMoveEvent.succeed()
                self.TrolleyMoveEvent.succeed()
                self.GantryMoveEvent = self.env.event()
                self.TrolleyMoveEvent = self.env.event()
                yield self.GantryMoveOverEvent & self.TrolleyMoveOverEvent
                self.InterruptFlag = False
                # 将作业状态设为有任务空闲状态
                self.StateCode = 0
                # 避让完成,进行下次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def GantryMove(self):
            while True:
                yield self.GantryMoveEvent
                self.GantryMoveEvent = self.env.event()
                while True:
                    self.GantryMoveingFlag = True
                    if self.CurrentPos[0] == self.TargetPos[0]:
                        break
                    else:
                        if self.CurrentPos[0] < self.TargetPos[0]:
                            ReachStackerPos = self.obj.ReachStacker.CurrentPos
                            while True:
                                if ReachStackerPos[0] == self.CurrentPos[
                                    0] + self.Safe_Distance and self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] += 1
                            # print("轨道吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            # print("当前时间为{}".format(self.env.now))
                        else:
                            ReachStackerPos = self.obj.ReachStacker.CurrentPos
                            while True:
                                if ReachStackerPos[0] == self.CurrentPos[
                                    0] - self.Safe_Distance and self.obj.ReachStacker.Worklinepos == Objective.WorkLinePos.Down:
                                    yield self.env.timeout(1)
                                else:
                                    break
                            try:
                                yield self.env.timeout(self.GANTRY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.GantryMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[0] -= 1
                            # print("轨道吊大车移动到贝位{}".format(self.CurrentPos[0]))
                            # print("当前时间为{}".format(self.env.now))
                self.GantryMoveingFlag = False
                self.GantryMoveOverEvent.succeed()
                self.GantryMoveOverEvent = self.env.event()

        def TrolleyMove(self):
            while True:
                yield self.TrolleyMoveEvent
                self.TrolleyMoveEvent = self.env.event()
                while True:
                    self.TrolleyMoveingFlag = True
                    if self.CurrentPos[1] == self.TargetPos[1]:
                        break
                    else:
                        if self.CurrentPos[1] < self.TargetPos[1]:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] += 1
                            # print("轨道吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            # print("当前时间为{}".format(self.env.now))
                        else:
                            try:
                                yield self.env.timeout(self.TROLLEY_SPEED)
                            except simpy.Interrupt:
                                self.InterruptFlag = True
                                self.TrolleyMoveProcessInterruptOver.succeed()
                                break
                            self.CurrentPos[1] -= 1
                            # print("轨道吊小车移动到栈位{}".format(self.CurrentPos[1]))
                            # print("当前时间为{}".format(self.env.now))
                self.TrolleyMoveingFlag = False
                self.TrolleyMoveOverEvent.succeed()
                self.TrolleyMoveOverEvent = self.env.event()

        def Pick(self):
            while True:
                yield self.PickEvent
                self.PickEvent = self.env.event()
                PickUpContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['StartPosition'][0],
                    self.CurrentTask['StartPosition'][1],
                    self.CurrentTask['StartPosition'][
                        2]).pop()
                # 进入抓取集装箱状态
                self.StateCode = 2
                if PickUpContainerLocation.level == 1:
                    Pick_Time = self.PICK1_TIME
                else:
                    Pick_Time = self.PICK2_TIME
                # 模拟抓取时间
                yield self.env.timeout(Pick_Time)
                self.LoadOn = True
                # 箱位状态调整
                PickUpContainerLocation.state = 0
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in Objective.ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                self.StateCode = 0
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Put(self):
            while True:
                yield self.PutEvent
                self.PutEvent = self.env.event()
                # 进入放置集装箱状态
                self.StateCode = 4
                PutContainerLocation = Objective.ContainerLocation.FindContainerLocation(
                    self.CurrentTask['EndPosition'][0],
                    self.CurrentTask['EndPosition'][1],
                    self.CurrentTask['EndPosition'][2]).pop()
                if PutContainerLocation.level == 1:
                    Put_time = self.PUT1_TIME
                else:
                    Put_time = self.PUT2_TIME
                # 模拟放置时间
                yield self.env.timeout(Put_time)
                self.LoadOn = False
                PutContainerLocation.state = 1
                # HTArray = np.zeros((2, 14, 66))
                # for object_ in ContainerLocation.ContainerList:
                #     HTArray[object_.level - 1, object_.stack - 1, object_.bay - 1] = object_.state
                # DrawPicture.ContainerChangeLocationList.append(copy.deepcopy(HTArray))
                # DrawPicture.ContainerChangeLocationTimeList.append(env.now)
                # 进入空闲状态
                self.StateCode = -2
                self.PutEvent = self.env.event()
                # 任务完成，清空任务
                self.CurrentTask.clear()
                self.TargetPos = self.CurrentPos
                Objective.CraneTaskQueue.pop(0)
                # 下一次调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)

        def Wait(self):
            while True:
                yield self.WaitEvent
                self.WaitEvent = self.env.event()
                if self.StateCode == -1:
                    self.StateCode = -1
                else:
                    self.StateCode = 0
                # 进入等待状态
                yield self.env.timeout(5)
                # 重置等待事件
                # 等待调度
                while True:
                    try:
                        Objective.ShaduleEvent.succeed(self)
                        break
                    except:
                        yield Objective.env.timeout(1)
                self.DeviceLock = False

        def InterruptWork(self):
            while True:
                yield self.InterruptWorkEvent
                if self.GantryMoveingFlag:
                    self.GantryMoveProcess.interrupt()
                    yield self.GantryMoveProcessInterruptOver
                    self.GantryMoveProcessInterruptOver = self.env.event()
                if self.TrolleyMoveingFlag:
                    self.TrolleyMoveProcess.interrupt()
                    yield self.TrolleyMoveProcessInterruptOver
                    self.TrolleyMoveProcessInterruptOver = self.env.event()


"""------------------------------------------绘图类-----------------------------------------"""


class Draw:
    # 初始化画布
    def __init__(self):
        # 创建画布
        self.fig = plt.figure(figsize=(10, 5))
        # 创建子图
        self.ax = self.fig.add_subplot(111)
        # 设定中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei']
        # 设定负号显示
        plt.rcParams['axes.unicode_minus'] = False
        # 设置标题
        self.ax.set_title('适应度曲线')
        # 设置坐标轴标签
        self.ax.set_xlabel('迭代次数')
        self.ax.set_ylabel('个体适应度')
        # 设置网格线
        self.ax.grid(True)
        # 设置坐标轴范围
        self.ax.set_xlim(1, ITERATION + 1)

    # 绘制适应度曲线
    def FintessCurve(self, BestFintess: Dict[int, float], AverageFintess: Dict[int, float]):
        # 绘制适应度曲线
        self.ax.plot(list(BestFintess.keys()), list(BestFintess.values()), 'r', linestyle='-', label='最优个体适应度')
        self.ax.plot(list(AverageFintess.keys()), list(AverageFintess.values()), 'b', linestyle='--',
                     label='种群平均适应度')
        # 添加图例
        self.ax.legend()
        # 存储图像
        plt.savefig("./实验图像/适应度曲线.png")
        # 显示图像
        plt.show()


"""------------------------------------------主函数-----------------------------------------"""
if __name__ == '__main__':
    obj = Objective()
    over_time, CranePos, ReachStackerPos = obj.evaluate(CraneTaskQueue, ReachStackerTaskQueue)
    # 定义历史状态
    state_old = -100
    count = 1
    Crane_state_count_list = []
    ReachStacker_state_count_list = []
    for elem in CranePos:
        state = elem[2]
        if state==-1:
            state = 5
        if state==-2:
            state = 6
        if state == state_old:
            count += 1
        else:
            element = [state_old, count]
            Crane_state_count_list.append(element)
            count = 1
            state_old = state
        if CranePos.index(elem) == len(CranePos) - 1:
            element = [state, count]
            Crane_state_count_list.append(element)
    for elem in ReachStackerPos:
        state = elem[2]
        if state==-1:
            state = 5
        if state==-2:
            state = 6
        if state == state_old:
            count += 1
        else:
            element = [state_old, count]
            ReachStacker_state_count_list.append(element)
            count = 1
            state_old = state
        if ReachStackerPos.index(elem) == len(ReachStackerPos) - 1:
            element = [state, count]
            ReachStacker_state_count_list.append(element)
    Crane_state_count_list.pop(0)
    ReachStacker_state_count_list.pop(0)
    count = 0
    for elem in Crane_state_count_list:
        count += elem[1]
    count = 0
    for elem in ReachStacker_state_count_list:
        count += elem[1]
    print(count)
    print(Crane_state_count_list)
    print(ReachStacker_state_count_list)
    Crane_state_dict = dict()
    ReachStacker_state_dict = dict()
    for elem in Crane_state_count_list:
        if elem[0] in Crane_state_dict.keys():
            Crane_state_dict[elem[0]] += elem[1]
        else:
            Crane_state_dict[elem[0]] = elem[1]
    for elem in ReachStacker_state_count_list:
        if elem[0] in ReachStacker_state_dict.keys():
            ReachStacker_state_dict[elem[0]] += elem[1]
        else:
            ReachStacker_state_dict[elem[0]] = elem[1]
    print(Crane_state_dict)
    print(ReachStacker_state_dict)



    # 乱码处理
    plt.rcParams['font.sans-serif'] = ['SimHei']
    fig, ax = plt.subplots(figsize=(8,5), dpi=300)
    left = 0
    label = ['有任务等待','空载移动','抓取作业','重载移动','放置作业','避让','无任务等待']
    hatch = ['xxxx', '', '\\\\', '----', '....', '****', '++++']
    color = ['white', 'gray', 'white', 'white', 'white', 'black', 'white']
    for elem in Crane_state_count_list:
        ax.barh(0.15, elem[1],height = 0.15, left=left,color=color[elem[0]], hatch = hatch[elem[0]],edgecolor='black',label=label[elem[0]])
        left += elem[1]
    left = 0
    for elem in ReachStacker_state_count_list:
        ax.barh(0.45, elem[1],height = 0.15, left=left,color=color[elem[0]], hatch = hatch[elem[0]],edgecolor='black',label=label[elem[0]])
        left += elem[1]
    handles, labels = plt.gca().get_legend_handles_labels()
    by_label = OrderedDict(zip(labels, handles))

    ax.set_yticks((0.15,0.45))  # 设置y轴刻度为0
    ax.set_yticklabels(['轨道吊','正面吊'])  # 设置y轴刻度标签为轨道吊
    plt.ylim((0,0.75))
    plt.xlabel('时间',fontsize=12)
    # 设置坐标轴刻度大小
    plt.xticks(fontsize=12)
    plt.yticks(fontsize=12)
    plt.legend(by_label.values(), by_label.keys(),fontsize=12,ncol = 2)
    plt.savefig("传统方法算例.svg", dpi=200, format="svg")
